package de.XPortLib;


/**
 * @author bbe
 *
 * Container for an Event
 */

public class TimerEvent {
	
	private int special;		// Special Event oder nicht?
	private int channel;		// Maske für die betroffenen Kanäle
	private int data;			// Werte für die betroffenen Kanäle
	
	private int second;		// Zeitpunkt des Ereignisses
	private int minute;		// wird ein Feld nicht benutzt, steht es 
	private int hour;			// auf DONTCARE
	private int day;
	private int month;
	private int year;		// Achtung das Jahr 255 bedeutet DONTCARE
	private int weekday;
	
	private int totalTimers;
	private int timerNr;
	
	public static int DONTCARE	= 255;
	public static int SIZE = 10;
	
	/* Create an Event without Data */
	public TimerEvent(){
		super();
		second	= DONTCARE;
		minute	= DONTCARE; 
		hour	= DONTCARE;
		day		= DONTCARE;
		month	= DONTCARE;
		year	= DONTCARE;
		weekday	= DONTCARE;
		timerNr = DONTCARE;
	}
	
	/* Create an Event from serial Data */
	public TimerEvent(int[] newData){
		this(newData, 0);
	}
	
	/* Create an Event from serial Data and adds total Timer count*/
	public TimerEvent(int[] newData, int timers){
		this();
		totalTimers = timers;
		timerFromSerial(newData);
	}	
	
	/* Initializes an event from a serial data Stream */
	public void timerFromSerial(int[] newData){
		int i=0;
		
		second= newData[i++];
		minute= newData[i++]; 
		hour=   newData[i++];
		day=    newData[i++];
		month=  newData[i++];
		year=   newData[i++] +  newData[i++]*256;
		weekday=newData[i++];
		
		special= (newData[i]>>7) & 1;
		channel=  newData[i++] & 0x7F;
		data=  newData[i++];

	}
	
	public String toString(){
		return timerNr == DONTCARE ? "NEW" : String.valueOf(timerNr);
	}

	public String toText(){
		String str = String.valueOf(timerNr) + " ";
		
		if (day==DONTCARE) str+="XX."; else str+=day+".";
		if (month==DONTCARE) str+="XX."; else str+=month+".";
		if (year==DONTCARE) str+="XXXX "; else str+=year+" ";

		str+=weekday+" ";
		
		if (hour==DONTCARE) str+="XX:"; else str+=day+":";
		if (minute==DONTCARE) str+="XX:"; else str+=minute+":";
		if (second==DONTCARE) str+="XXXX "; else str+=second+" ";

		str+="Type: "+special+" Ch: "+channel+" Value: "+data;
		return str;
	}
	
	public int[] getSerial(){
		int[] serial = new int[SIZE];
		
		int i=0;
				
		serial[i++]= second;		// Zeitpunkt des Ereignisses
		serial[i++]= minute;		// wird ein Feld nicht benutzt, steht es 
		serial[i++]= hour;			// auf DONTCARE
		serial[i++]= day;
		serial[i++]= month;
		serial[i++]= year & 0xFF;		// Achtung das Jahr 255 bedeutet DONTCARE
		serial[i++]= (year /256) &0xFF;		// Achtung das Jahr 255 bedeutet DONTCARE
		
		serial[i++]=weekday;
		
		serial[i++]= (channel & 0x7F) | ((special << 7) & 0x80);		// Maske für die betroffenen Kanäle
		serial[i++]= data;			// Werte für die betroffenen Kanäle

		
		return serial;
	}
	/**
	 * @return Returns the channel.
	 */
	public int getChannel() {
		return channel;
	}
	/**
	 * @param channel The channel to set.
	 */
	public void setChannel(int channel) {
		this.channel = channel;
	}
	/**
	 * @return Returns the data.
	 */
	public int getData() {
		return data;
	}
	/**
	 * @param data The data to set.
	 */
	public void setData(int data) {
		this.data = data;
	}
	/**
	 * @return Returns the day.
	 */
	public int getDay() {
		return day;
	}
	/**
	 * @param day The day to set.
	 */
	public void setDay(int day) {
		this.day = day;
	}
	/**
	 * @return Returns the hour.
	 */
	public int getHour() {
		return hour;
	}
	/**
	 * @param hour The hour to set.
	 */
	public void setHour(int hour) {
		this.hour = hour;
	}
	/**
	 * @return Returns the minute.
	 */
	public int getMinute() {
		return minute;
	}
	/**
	 * @param minute The minute to set.
	 */
	public void setMinute(int minute) {
		this.minute = minute;
	}
	/**
	 * @return Returns the month.
	 */
	public int getMonth() {
		return month;
	}
	/**
	 * @param month The month to set.
	 */
	public void setMonth(int month) {
		this.month = month;
	}
	/**
	 * @return Returns the second.
	 */
	public int getSecond() {
		return second;
	}
	/**
	 * @param second The second to set.
	 */
	public void setSecond(int second) {
		this.second = second;
	}
	/**
	 * @return Returns the year.
	 */
	public int getYear() {
		return year;
	}
	/**
	 * @param year The year to set.
	 */
	public void setYear(int year) {
		this.year = year;
	}
	/**
	 * @return Returns the weekday.
	 */
	public int getWeekday() {
		return weekday;
	}
	/**
	 * @param weekday The weekday to set.
	 */
	public void setWeekday(int weekday) {
		this.weekday = weekday;
	}
	/**
	 * @return Returns the special.
	 */
	public boolean getSpecial() {
		if (special==0) 
			return false;
		else
			return true;
	}
	/**
	 * @param special The special to set.
	 */
	public void setSpecial(boolean special) {
		if (special==true)
			this.special = 1;
		else 
			this.special = 0;
	}
	
	/**
	 * @return the totalTimers
	 */
	public int getTotalTimers() {
		return totalTimers;
	}

	/**
	 * @return the timerNr
	 */
	public int getTimerNr() {
		return timerNr;
	}

	/**
	 * @param timerNr the timerNr to set
	 */
	public void setTimerNr(int timerNr) {
		this.timerNr = timerNr;
	}
	
	public void setWeekday(int[] weekdays) {
		weekday = indexArrayToBitField(weekdays);
	}
	
	public int[] getWeekdays() {
		return bitFieldToIndexArray(weekday);
	}
	
	public void setChannel(int[] channels) {
		channel = indexArrayToBitField(channels);
	}
	
	public int[] getChannels() {
		return bitFieldToIndexArray(channel);
	}
	
	public void setData(int[] data) {
		this.data = indexArrayToBitField(data);
	}
	
	public int[] getDataArray() {
		return bitFieldToIndexArray(data);
	}
	
	/**
	 * converts a 7-bit integer bitfield into an array filled with the bits that are set.
	 * @param bitfield
	 * 			bitfield to convert
	 * @return
	 * 			arrary with indices / set bits
	 */
	private int[] bitFieldToIndexArray(int bitfield) {
		int size = 7;
		int[] indexArray = new int[size];
		int arrayIndex = 0;
		bitfield &= 127;
		
		for(int i = 0; i < size; i++) {
			if (bitfield % 2 == 1) {
				indexArray[arrayIndex++] = i;
			}
			bitfield /= 2;
		}
		for(int i = arrayIndex; i < size; i++) {
			indexArray[i] = arrayIndex == 0 ? -1 : indexArray[arrayIndex - 1];
		}
		
		return indexArray;
	}
	
	/**
	 * converts an indexArray into a bitfield 
	 * @param indexArray
	 * @return
	 */
	private int indexArrayToBitField(int[] indexArray) {
		int bitfield = 0;
		for(int x : indexArray) {
			bitfield += Math.pow(2, x);
		}
		return bitfield & 255;
	}
	
}
